<?php

namespace util;

/**
 * xml工具类
 *
 * @author fuyou<fuyou@dangdang.com>
 * @since May 22, 2015 2:52:03 PM
 * @version 2.0
 * @copyright (c) 2015 , DANG
 *           
 */
class XMLUtil {
    public static function arrayToXml(array $array, $rootname = 'resultObject') {
        $r = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>' . "\n" . '<' . $rootname . '>' . "\n";
        if (! empty ( $array ))
            foreach ( $array as $k => $v )
                self::o2x ( $r, $k, $v );
        $r .= '</' . $rootname . '>';
        return $r;
    }
    public static function array2xmls(array $array, $rootname = 'resultObject') {
        $r = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . '<' . $rootname . '>' . "\n";
        if (! empty ( $array )) {
            foreach ( $array as $k => $v ) {
                if (! empty ( $v )) {
                    foreach ( $v as $kk => $vv )
                        self::o2x ( $r, $kk, $vv );
                }
            }
        }
        $r .= '</' . $rootname . '>';
        return $r;
    }
    /*
     * function changeArray2Xml
     * 将array转换为.net webservice xml参数
     * @input array
     * @output string
     */
    public static function changeArray2Xml($arr) {
        $xml = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>';
        $xml .= '<inputObject>';
        $xml_list = '';
        $flag = false;
        foreach ( $arr as $key => $value ) {
            $type = gettype ( $value );
            if ($type == "array") {
                $flag = true;
                $xml_list .= '<row>';
                foreach ( $value as $vkey => $v ) {
                    $xml_list .= self::makeXmlBody ( $vkey, $v );
                }
                $xml_list .= '</row>';
            } else {
                $xml_list .= self::makeXmlBody ( $key, $value );
            }
        }
        if ($flag)
            $xml_list = '<dbvalue>' . $xml_list . '</dbvalue>';
        $xml .= $xml_list . '</inputObject>';
        return $xml;
    }
    /*
     * function makeXmlBody
     * 通过输入的键值生成xml代码
     * @input: mix $key,mix $value
     * @output: string
     */
    private static function makeXmlBody($key, $value) {
        $xmlbody = '<' . $key . '>';
        $xmlbody .= '<![CDATA[' . $value . ']]>';
        $xmlbody .= '</' . $key . '>';
        return $xmlbody;
    }
    /* 将数组格式化为POST的XML字符串 */
    public static function array2xml($array, $level = 0) {
        $return = '';
        if ($level == 0) {
            $return = '<?xml version="1.0" encoding="utf-8" ?><root>';
        }
        foreach ( $array as $key => $item ) {
            if (! is_array ( $item )) {
                $return .= "<{$key}>{$item}</{$key}>";
            } else {
                $return .= "<{$key}>";
                $return .= self::array2xml ( $item, $level + 1 );
                $return .= "</{$key}>";
            }
        }
        if ($level == 0) {
            $return .= '</root>';
        }
        return $return;
    }
    // 貌似有bug...改使用object2array
    public static function xmlToArray($xml) {
        $return = self::hhvmXmlToArray ( $xml );
        if (is_array ( $return ) && ! empty ( $return )) {
            foreach ( $return as $k => $v ) {
                return $v;
            }
        }
    }
    public static function a2x(&$r, $k, array $v) {
        $r .= "<$k>" . "\n";
        foreach ( $v as $kk => $vv )
            self::o2x ( $r, $kk, $vv );
        $r .= "</$k>" . "\n";
    }
    public static function o2x(&$r, $k, $v) {
        if (is_numeric ( $k ) && is_array ( $v )) {
            self::a2x ( $r, 'row', $v );
        } else if (is_numeric ( $k )) {
            $r .= "<row><![CDATA[$v]]></row>" . "\n";
        } else if (is_array ( $v )) {
            self::a2x ( $r, $k, $v );
        } else if (is_numeric ( $v )) {
            $r .= "<$k>$v</$k>" . "\n";
        } else if (is_bool ( $v )) {
            $r .= "<$k>" . intval ( $v ) . "</$k>" . "\n";
        } else {
            $r .= "<$k><![CDATA[$v]]></$k>" . "\n";
        }
    }
    public static function object2Array($object) {
        $return = null;
        if (is_array ( $object )) {
            foreach ( $object as $key => $value ) {
                $return [$key] = self::object2array ( $value );
            }
        } else {
            $var = get_object_vars ( $object );
            if ($var) {
                foreach ( $var as $key => $value ) {
                    $return [$key] = self::object2array ( $value );
                }
            } else {
                return trim ( strval ( $object ) );
            }
        }
        
        return $return;
    }
    /**
     * 将xml转化为数组
     *
     * @param unknown $contents            
     * @param string $get_attributes            
     * @param string $tag_priority            
     * @return multitype:
     * @since May 20, 2015 4:02:56 PM
     * @access
     *
     */
    public static function hhvmXmlToArray($contents, $get_attributes = true, $tag_priority = true) {
        $contents = \util\ComFunc::convertXmlEncode ( $contents );
        $contents = trim ( $contents );
        if (empty ( $contents )) {
            return array ();
        }
        $parser = xml_parser_create ( '' );
        xml_parser_set_option ( $parser, XML_OPTION_TARGET_ENCODING, 'utf-8' );
        xml_parser_set_option ( $parser, XML_OPTION_CASE_FOLDING, 0 );
        xml_parser_set_option ( $parser, XML_OPTION_SKIP_WHITE, 1 );
        if (xml_parse_into_struct ( $parser, $contents, $xml_values ) == 0) {
            xml_parser_free ( $parser );
            return array ();
        }
        xml_parser_free ( $parser );
        if (! $xml_values) {
            return array ();
        }
        unset ( $contents, $parser );
        $xml_array = array ();
        $current = &$xml_array;
        $repeated_tag_index = array ();
        foreach ( $xml_values as $num => $xml_tag ) {
            $result = "";
            $attributes_data = null;
            if (isset ( $xml_tag ['value'] )) {
                if ($tag_priority) {
                    $result = $xml_tag ['value'];
                } else {
                    $result ['value'] = $xml_tag ['value'];
                }
            }
            if (isset ( $xml_tag ['attributes'] ) and $get_attributes) {
                foreach ( $xml_tag ['attributes'] as $attr => $val ) {
                    if ($tag_priority) {
                        $attributes_data [$attr] = $val;
                    } else {
                        $result ['@attributes'] [$attr] = $val;
                    }
                }
            }
            if ($xml_tag ['type'] == 'open') {
                $parent [$xml_tag ['level'] - 1] = &$current;
                if (! is_array ( $current ) or (! in_array ( $xml_tag ['tag'], array_keys ( $current ) ))) {
                    $current [$xml_tag ['tag']] = $result;
                    unset ( $result );
                    if ($attributes_data)
                        $current ['@' . $xml_tag ['tag']] = $attributes_data;
                    $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] = 1;
                    $current = &$current [$xml_tag ['tag']];
                } else {
                    if (isset ( $current [$xml_tag ['tag']] ['0'] )) {
                        $current [$xml_tag ['tag']] [$repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']]] = $result;
                        unset ( $result );
                        if ($attributes_data) {
                            if (isset ( $repeated_tag_index ['@' . $xml_tag ['tag'] . '_' . $xml_tag ['level']] )) {
                                $current [$xml_tag ['tag']] [$repeated_tag_index ['@' . $xml_tag ['tag'] . '_' . $xml_tag ['level']]] = $attributes_data;
                            }
                            $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] ++;
                        }
                    } else {
                        $current [$xml_tag ['tag']] = array (
                                $current [$xml_tag ['tag']],
                                $result 
                        );
                        unset ( $result );
                        $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] = 2;
                        if (isset ( $current ['@' . $xml_tag ['tag']] )) {
                            $current [$xml_tag ['tag']] ['@0'] = $current ['@' . $xml_tag ['tag']];
                            unset ( $current ['@' . $xml_tag ['tag']] );
                        }
                        if ($attributes_data) {
                            $current [$xml_tag ['tag']] ['@1'] = $attributes_data;
                        }
                    }
                    $last_item_index = $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] - 1;
                    $current = &$current [$xml_tag ['tag']] [$last_item_index];
                }
            } elseif ($xml_tag ['type'] == 'complete') {
                if (! isset ( $current [$xml_tag ['tag']] ) and empty ( $current ['@' . $xml_tag ['tag']] )) {
                    $current [$xml_tag ['tag']] = $result;
                    unset ( $result );
                    $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] = 1;
                    if ($tag_priority and $attributes_data) {
                        $current ['@' . $xml_tag ['tag']] = $attributes_data;
                    }
                } else {
                    if (isset ( $current [$xml_tag ['tag']] ['0'] ) and is_array ( $current [$xml_tag ['tag']] )) {
                        $current [$xml_tag ['tag']] [$repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']]] = $result;
                        unset ( $result );
                        if ($tag_priority and $get_attributes and $attributes_data) {
                            $current [$xml_tag ['tag']] ['@' . $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']]] = $attributes_data;
                        }
                        $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] ++;
                    } else {
                        $current [$xml_tag ['tag']] = array (
                                $current [$xml_tag ['tag']],
                                $result 
                        );
                        unset ( $result );
                        $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] = 1;
                        if ($tag_priority and $get_attributes) {
                            if (isset ( $current ['@' . $xml_tag ['tag']] )) {
                                $current [$xml_tag ['tag']] ['@0'] = $current ['@' . $xml_tag ['tag']];
                                unset ( $current ['@' . $xml_tag ['tag']] );
                            }
                            if ($attributes_data) {
                                $current [$xml_tag ['tag']] ['@' . $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']]] = $attributes_data;
                            }
                        }
                        $repeated_tag_index [$xml_tag ['tag'] . '_' . $xml_tag ['level']] ++;
                    }
                }
            } elseif ($xml_tag ['type'] == 'close') {
                $current = &$parent [$xml_tag ['level'] - 1];
            }
            unset ( $xml_values [$num] );
        }
        return $xml_array;
    }
}
?>